namespace Digitalmes.Common.Cache;

/// <summary>
/// 基于内存的缓存。
/// </summary>
public sealed class MemoryService : ICacheService
{
    private readonly IMemoryCache _cache;

    public MemoryService(IMemoryCache cache)
    {
        _cache = cache;
    }

    /// <summary>
    /// 缓存服务实例
    /// </summary>
    public static readonly MemoryService Default;

    static MemoryService()
    {
        Default = new MemoryService(new MemoryCache(new MemoryCacheOptions()));
    }

    /// <summary>
    /// 是否存在此缓存
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public bool Exists(string key)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentNullException(nameof(key));

        return _cache.TryGetValue<object>(key, out _);
    }

    /// <summary>
    /// 取得缓存数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    public T GetCache<T>(string key) where T : class
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentNullException(nameof(key));

        _cache.TryGetValue(key, out T v);
        return v;
    }

    /// <summary>
    /// 设置缓存
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    public void SetCache<T>(string key, T value)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentNullException(nameof(key));
        if (value == null)
            throw new ArgumentNullException(nameof(value));

        if (_cache.TryGetValue(key, out _))
            _cache.Remove(key);

        _cache.Set(key, value);
    }

    /// <summary>
    /// 设置缓存,绝对过期
    /// </summary>
    /// <param name="key">key</param>
    /// <param name="value">值</param>
    /// <param name="expirationMinute">间隔分钟</param>
    public void SetCache<T>(string key, T value, double expirationMinute)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentNullException(nameof(key));
        if (value == null)
            throw new ArgumentNullException(nameof(value));

        if (_cache.TryGetValue(key, out _))
            _cache.Remove(key);

        DateTime now = DateTime.Now;
        TimeSpan ts = now.AddMinutes(expirationMinute) - DateTime.Now;
        _cache.Set(key, value, ts);
    }

    /// <summary>
    /// 设置缓存,绝对过期
    /// </summary>
    /// <param name="key">key</param>
    /// <param name="value">值</param>
    /// <param name="expirationTime">绝对过期时间，如 DateTimeOffset.Now.AddSeconds(30)</param>
    public void SetCache<T>(string key, T value, DateTimeOffset expirationTime)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentNullException(nameof(key));
        if (value == null)
            throw new ArgumentNullException(nameof(value));

        if (_cache.TryGetValue(key, out _))
            _cache.Remove(key);

        _cache.Set(key, value, expirationTime);
    }

    /// <summary>
    /// 设置缓存,相对过期时间
    /// </summary>
    /// <param name="key">key</param>
    /// <param name="value">值</param>
    /// <param name="t">相对过期时间</param>
    public void SetSlidingCache<T>(string key, T value, TimeSpan t)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentNullException(nameof(key));
        if (value == null)
            throw new ArgumentNullException(nameof(value));

        if (_cache.TryGetValue(key, out _))
            _cache.Remove(key);

        _cache.Set(key, value, new MemoryCacheEntryOptions()
        {
            SlidingExpiration = t,
        });
    }

    /// <summary>
    /// 移除缓存
    /// </summary>
    /// <param name="key">key</param>
    public void RemoveCache(string key)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentNullException(nameof(key));

        _cache.Remove(key);
    }

    /// <summary>
    /// 释放
    /// </summary>
    public void Dispose()
    {
        _cache?.Dispose();
    }
}
